/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-05-09     IBM       the first version
 */
#include "tm1638.h"
#include "app.h"

static const char *TAG = "user_tm1638";

/*=====================================================### 全局变量定义 ####=================================================*/
// uint8_t segmented[10] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f}; // 段码值
uint8_t segmented[] = {0x3f, 0x03, 0x6d, 0x67, 0x53, 0x76, 0x7e, 0x23, 0x7f, 0x77, 0x00}; // 段码值
uint16_t buffer[8] = {0};                                                                 // 数据缓冲器
uint8_t sendData[16] = {0};                                                               // 发送数据缓冲区



extern tSys_Status Sys_Status;
extern tSys_Flag Sys_Flag;

extern SemaphoreHandle_t sem_Dis_Change_Flag;

/*=====================================================#######  END  #######=================================================*/

/*=====================================================### 静态函数调用 ###==================================================*/
/**
 * @brief TM1638发送数据
 * @param DATA：数据
 */
static void TM1638_Write(uint8_t DATA)
{
    uint8_t i;

    for (i = 0; i < 8; i++) // 1Byte 8位数据
    {
        TM1638_CLK_LOW; // 拉低时钟线
        us_delay(10);
        if (DATA & 0x01) // 发送数据
        {
            TM1638_DIO_HIGH;
        }
        else
        {
            TM1638_DIO_LOW;
        }
        us_delay(10);
        DATA >>= 1;      // 数据格式:低位在前
        TM1638_CLK_HIGH; // 拉高时钟线,写入数据
        us_delay(10);
    }
}

static uint8_t TM1638_Read(void)
{
    uint8_t i, Data = 0;

    TM1638_DIO_HIGH; // 初始化数据线

    us_delay(10);
    for (i = 0; i < 8; i++)
    {
        Data >>= 1; // 数据格式:低位在前
        TM1638_CLK_LOW;
        us_delay(10);
        if (TM1638_GET_DIO == 1)
            Data |= 0x80;
        TM1638_CLK_HIGH;
        us_delay(10);
    }
    return Data;
}

uint32_t TM1638_ReadKey(void)
{
    uint8_t c[4]; // 4Byte数据储存
    uint32_t key_value = 0;
    // uint16_t key_num = 0;

    TM1638_STB_LOW; // 拉低片选线,开始读键值
    us_delay(10);
    TM1638_Write(0x42); // 写'读数据'命令
    us_delay(10);

    for (int i = 0; i < 2; i++) // 读取2个Byte
        c[i] = TM1638_Read();

    TM1638_STB_HIGH; // 拉高片选线,读键值结束
    us_delay(10);

    key_value = c[0] + (c[1] << 8);
    return (key_value); // 返回键值
}

/**
 * @brief TM1638发送命令
 * @param cmd
 */
static void TM1638_WriteCOM(uint8_t cmd)
{
    TM1638_STB_LOW; // 拉低片选线
    us_delay(10);
    TM1638_Write(cmd); // 写命令
    us_delay(10);
    TM1638_STB_HIGH; // 拉高片选线
    us_delay(10);
}

/**
 * @brief 单个数码管显示值
 * @param lednum ：数码管编号 1 - 9
 * @param value  ：显示的值 0 - 9
 * @param decimal：是否带小数点  0 - 不带  1 - 带
 */
static void LED_Display_Value(uint8_t lednum, uint8_t value)
{
    //uint8_t i;
    lednum -= 1;
    if (lednum < 5) // 前5段数码管
    {
        buffer[lednum] = segmented[value];
    }
    else if (lednum == 5)
    {
        if (value > 0 && value < 10)
            buffer[lednum] = segmented[1];
        else
            buffer[lednum] = buffer[lednum] & (~segmented[1]);
    }
}

/**
 * @brief u16数据转成u8数据
 */
static void Data_U16_To_U8(void)
{
    for (int i = 0; i < 16; i += 2)
    {
        sendData[i] = buffer[i / 2];
        sendData[i + 1] = buffer[i / 2] >> 8;
    }
}

/**
 * @brief 发送数据到数码管
 */
static void Send_Data_To_LED(void)
{
    Data_U16_To_U8();

    TM1638_STB_LOW; // 拉低片选线,开始写数据
    us_delay(10);
    TM1638_Write(REG_FIRST_ADDR); // 写首地址
    us_delay(10);
    for (int i = 0; i < 16; ++i) // 发数据
    {
        TM1638_Write(sendData[i]);
    }
    us_delay(10);
    TM1638_STB_HIGH;
    us_delay(10);
}

/**
 * @brief 关闭LED数码管显示
 */
static void LED_Close_Display(void)
{
    memset(buffer, 0, sizeof(buffer));
    Data_U16_To_U8();
    Send_Data_To_LED();
}
/*=====================================================#######  END  #######=================================================*/

/*=====================================================##### 外部调用 #####==================================================*/

void TM1638_Configure_Gpio(void)
{
    gpio_config_t gpio_cfg =
        {
            .pin_bit_mask = (1 << TM1638_STB) | (1 << TM1638_CLK),
            .pull_down_en = GPIO_PULLDOWN_DISABLE,
            .pull_up_en = GPIO_PULLUP_ENABLE,
            .mode = GPIO_MODE_OUTPUT,
            .intr_type = GPIO_INTR_DISABLE,
        };

    gpio_config(&gpio_cfg);

    gpio_cfg.pin_bit_mask = (1 << TM1638_DIO); // 设置为开漏输入输出模式
    gpio_cfg.mode = GPIO_MODE_INPUT_OUTPUT_OD;
    gpio_config(&gpio_cfg);
}

/**
 * @brief TM1638初始化设置
 */
void TM1638_Init(void)
{
    TM1638_Configure_Gpio();

    TM1638_WriteCOM(DATA_CMD_ADDR);    // 设置地址自增

    LED_Close_Display();

    TM1638_WriteCOM(LED_DISPLAY_ADDR);    // LED亮度设置
}



void Set_Streng_Display(int8_t value)
{
    if (value < 100)
    {
        LED_Display_Value(1, value % 10);
        LED_Display_Value(2, value / 10 % 10);
    }
}

void Set_Time_Display(int32_t value)
{
    int val = 0;
    if (value >= (99 * 60))
    {
        value = 99 * 60;
    }
    if(value != 0)
        val = (value - 1) / 60 + 1; // 为了不显示31  手动减一秒

    LED_Display_Value(3, val % 10);
    LED_Display_Value(4, val / 10 % 10);
}

void Set_Mode_Display(int8_t value)
{
    if (value < 11)
    {
        LED_Display_Value(5, value % 10);
        LED_Display_Value(6, value / 10 % 10);
    }
}

void Set_Heat_Display(int8_t value)
{

    switch (value)
    {
    case 0:
        //buffer[5] &= ~(1 << 5); // 关闭加热灯
        buffer[6] = (buffer[6] & 0x1F);
        break;
    case 1:
        //buffer[5] |= (1 << 5); // 打开加热灯
        buffer[6] = (buffer[6] & 0x1F) | (1 << 5);
        break;
    case 2:
        //buffer[5] |= (1 << 5); // 打开加热灯
        buffer[6] = (buffer[6] & 0x1F) | (3 << 5);
        break;
    case 3:
        //buffer[5] |= (1 << 5); // 打开加热灯
        buffer[6] = (buffer[6] & 0x1F) | (7 << 5);
        break;
    default:
        break;
    }
    //ESP_LOGI(TAG, "buffer[5] = 0x%02x , buffer[6] = 0x%02x", buffer[5], buffer[6]);
}

void Set_Led_Flag_Display(void)
{
    if (Sys_Flag.Led_Ble_Flag == 1)
        buffer[6] |= 1 << 0;
    else
        buffer[6] &= ~(1 << 0);

    if (Sys_Flag.Led_Wifi_Flag == 1)
        buffer[6] |= 1 << 1;
    else
        buffer[6] &= ~(1 << 1);

    if (Sys_Flag.Led_Heat_Flag == 1)
        buffer[6] |= 1 << 2;
    else
        buffer[6] &= ~(1 << 2);

    if (Sys_Flag.Led_Time_Flag == 1)
        buffer[6] |= 1 << 3;
    else
        buffer[6] &= ~(1 << 3);

    if (Sys_Flag.Led_Start_Flag == 1)
        buffer[6] |= 1 << 4;
    else
        buffer[6] &= ~(1 << 4);

    if (Sys_Flag.Led_Mode_Num_Flag == 1)
        buffer[5] |= 1 << 2;
    else
        buffer[5] &= ~(1 << 2);

    if (Sys_Flag.Led_Time_Num_Flag == 1)
        buffer[5] |= 1 << 3;
    else
        buffer[5] &= ~(1 << 3);

    if (Sys_Flag.Led_Streng_Num_Flag == 1)
        buffer[5] |= 1 << 4;
    else
        buffer[5] &= ~(1 << 4);

    if (Sys_Flag.Led_Heat_Num_Flag == 1)
        buffer[5] |= 1 << 5;
    else
        buffer[5] &= ~(1 << 5);

    if (Sys_Flag.Led_Minute_Flag == 1)
        buffer[5] |= 1 << 6;
    else
        buffer[5] &= ~(1 << 6);

  //  ESP_LOGI(TAG, "buffer[6] = 0x%02x ", buffer[6]);
}

void Led_Flash_Fun(void)
{
    if (Sys_Status.Led_Flash_Time != 0)
    {
        Sys_Status.Led_Flash_Time--;
        //ESP_LOGI(TAG, "Sys_Flag.Led_Flash_Time =  %d", (int)Sys_Status.Led_Flash_Time);
        if (Sys_Status.Led_Flash_Time == 0)
        {
            switch (Sys_Status.Argument_Value)
            {
            case Arg_Mode:
                Sys_Flag.Led_Mode_Num_Flag = 1;
                break;
            case Arg_Time:
                Sys_Flag.Led_Time_Num_Flag = 1;
                break;
            case Arg_Streng:
                Sys_Flag.Led_Streng_Num_Flag = 1;
                break;
            case Arg_Heat:
                Sys_Flag.Led_Heat_Num_Flag = 1;
                break;
            default:
                break;
            }
            Sys_Status.Argument_Value = Arg_None;
            xSemaphoreGive(sem_Dis_Change_Flag);
        }
        else if ((Sys_Status.Led_Flash_Time % 5) == 0)
        {
            switch (Sys_Status.Argument_Value)
            {
            case Arg_Mode:
                Sys_Flag.Led_Mode_Num_Flag = !Sys_Flag.Led_Mode_Num_Flag;
                Sys_Flag.Led_Time_Num_Flag = 1;
                Sys_Flag.Led_Streng_Num_Flag = 1;
                Sys_Flag.Led_Heat_Num_Flag = 1;
                break;
            case Arg_Time:
                Sys_Flag.Led_Mode_Num_Flag = 1;
                Sys_Flag.Led_Time_Num_Flag = !Sys_Flag.Led_Time_Num_Flag;
                Sys_Flag.Led_Streng_Num_Flag = 1;
                Sys_Flag.Led_Heat_Num_Flag = 1;
                break;
            case Arg_Streng:
                Sys_Flag.Led_Mode_Num_Flag = 1;
                Sys_Flag.Led_Time_Num_Flag = 1;
                Sys_Flag.Led_Streng_Num_Flag = !Sys_Flag.Led_Streng_Num_Flag;
                Sys_Flag.Led_Heat_Num_Flag = 1;
                break;
            case Arg_Heat:
                Sys_Flag.Led_Mode_Num_Flag = 1;
                Sys_Flag.Led_Time_Num_Flag = 1;
                Sys_Flag.Led_Streng_Num_Flag = 1;
                Sys_Flag.Led_Heat_Num_Flag = !Sys_Flag.Led_Heat_Num_Flag;
                break;
            default:
                break;
            }
            xSemaphoreGive(sem_Dis_Change_Flag);
        }
    }
    else
    {
        if (Sys_Flag.Led_Mode_Num_Flag != 1)
            Sys_Flag.Led_Mode_Num_Flag = 1;
        if (Sys_Flag.Led_Time_Num_Flag != 1)
            Sys_Flag.Led_Time_Num_Flag = 1;
        if (Sys_Flag.Led_Streng_Num_Flag != 1)
            Sys_Flag.Led_Streng_Num_Flag = 1;
        if (Sys_Flag.Led_Heat_Num_Flag != 1)
            Sys_Flag.Led_Heat_Num_Flag = 1;
        if (Sys_Status.Argument_Value != Arg_None)
            Sys_Status.Argument_Value = Arg_None;
    }
}

SemaphoreHandle_t sem_Key_Value;
SemaphoreHandle_t sem_Dis_Change_Flag;
extern SemaphoreHandle_t sem_Pwm_Change;

/**
 * @brief 测试demo程序
 */
void TM1638_Task(void *param)
{
    uint32_t Key_Num = 0;
    uint32_t current_time =0 , old_time = 0;
    int tt = 0 ; // 按键持续按压标记位

    TM1638_Init();
    

    sem_Key_Value = xSemaphoreCreateBinary();   // 创建按键信号量
    sem_Dis_Change_Flag = xSemaphoreCreateBinary();   // 创建显示更新信号量

    while (1)
    {

        Key_Num = TM1638_ReadKey();
        if (Key_Num != 0)
        {
            if (tt == 0)    // 单次按键触发
            {
                tt = 1;
                vTaskDelay(10);
                if (Key_Num == TM1638_ReadKey())
                {
                    Sys_Status.Key_Vaule = Key_Num;
                    Sys_Flag.Key_Sustain_Flag = 0;
                    xSemaphoreGive(sem_Key_Value);
                }
            }
            else        // 持续按键触发
            {
                if( tt > 10 && Sys_Flag.Key_Sustain_Flag != 1)
                {
                   Sys_Flag.Key_Sustain_Flag = 1;   // 持续按压有效标记位
                   xSemaphoreGive(sem_Key_Value);
                   tt = 9;
                }
                else
                    tt++;
            }
        }
        else if (tt != 0 || Sys_Flag.Key_Sustain_Flag != 0 || Sys_Status.Key_Vaule != 0)
        {
            tt = 0;
            Sys_Flag.Key_Sustain_Flag = 0;
            Sys_Status.Key_Vaule = 0;
        }

        if (xSemaphoreTake(sem_Dis_Change_Flag, 1) == pdTRUE) // 不阻塞的信号量获取   // 是否需要更新显示
        {
            if (Sys_Flag.System_Power == 1)
            {
                Set_Mode_Display(Sys_Status.Mode_Value);
                Set_Time_Display(Sys_Status.Time_Value);
                Set_Streng_Display(Sys_Status.Streng_Value);
                Set_Heat_Display(Sys_Status.Heat_Value);
                Set_Led_Flag_Display();
                Send_Data_To_LED();
            }
            else
            {
                if (Sys_Status.Led_Flash_Time != 0)
                    Sys_Status.Led_Flash_Time = 0;
                LED_Close_Display();
            }
        }

        if (Sys_Flag.System_Power == 1)
        {
            current_time = esp_timer_get_time() / 1000000; // 获取当前时间（豪秒）

            if (current_time != old_time) 
            {
                old_time = current_time;
                //ESP_LOGI(TAG, "current_time =  %d", (int)esp_timer_get_time());
                if (Sys_Flag.Led_Start_Flag == 1)
                {
                    if (Sys_Status.Time_Value > 0)
                        Sys_Status.Time_Value--;
                    else
                    {
                        Sys_Flag.Led_Start_Flag = 0;
                        Sys_Flag.Led_Minute_Flag = 1;

                        User_Uart_Send_Data("S18");
                        xSemaphoreGive(sem_Pwm_Change);
                    }
                    Sys_Flag.Led_Minute_Flag = !Sys_Flag.Led_Minute_Flag;
                    xSemaphoreGive(sem_Dis_Change_Flag);
                }
            }

            Led_Flash_Fun(); // 0.5秒切换一次，所以不在1秒任务里面
        }

        vTaskDelay(100);
    }
}

/*=====================================================#######  END  #######=================================================*/
